#include "aIO.h"
#include "aStem.h"
#include <time.h>
#include "acpFilter.h"

#include <fstream>
using namespace std;

////////////////////////////////////////////////////////////////////

#define aHISTORY 10
#define aUSESTEM
#define aUSEKALMANFILTER


////////////////////////////////////////////////////////////////////

class acpTemperature {
public:
  acpTemperature(void);
  ~acpTemperature(void);
  void init(void);
  void history_print();
  void sendMsg(const int status);
  void record(void);
  
  bool isConnected() { return !m_stem.isConnected(); }
  
private:
  acpStem m_stem;
  aSettingFileRef m_settings;
  aIOLib m_ioref;
  aFileRef m_dataFile;
  
  int m_historySize;
  int m_history[100];
  void history_update(const int value);
  int m_delay;
  int m_sampleNum;
  
  char* m_msgRecepient;
  
  acpString m_dataFileName;
#ifdef aUSEKALMANFILTER
  acpKalmanFilter m_filter;
#else
  acpMovingAverageFilter m_filter;
#endif
  acpMovingAverageFilter m_filterAvg;
};

////////////////////////////////////////////////////////////////////

acpTemperature::acpTemperature()
{
  aIO_GetLibRef(&m_ioref, NULL);
}

acpTemperature::~acpTemperature()
{
  aFile_Close(m_ioref, m_dataFile, NULL);
  
  aIO_ReleaseLibRef(m_ioref, NULL);
}

////////////////////////////////////////////////////////////////////
// Create settings and initialize
void
acpTemperature::init()
{
  
  aSettingFile_Create(m_ioref, 32, "temperature.config", 
		      &m_settings, NULL);
  
  aSettingFile_GetString(m_ioref, m_settings, 
			 "recipient", &m_msgRecepient, "", NULL);
  
  aSettingFile_GetInt(m_ioref, m_settings, 
		      "delay", &m_delay, 500, NULL);
  
  aSettingFile_GetInt(m_ioref, m_settings, 
		      "history", &m_historySize, 100, NULL);
  
  // Set the history buffer to all zeros
  for(int i = 0; i < m_historySize; i++)
    m_history[i] = 0;
  
  // Get data file logging information
  char* dfile;
  aSettingFile_GetString(m_ioref, m_settings, 
			 "datafile", &dfile, "", NULL);
  m_dataFileName = dfile;
  m_dataFileName += "data.txt";
  
  // Set the number of samples to zero
  m_sampleNum = 0;
  
  ofstream LogDataFile((char*)m_dataFileName, ios::trunc);
  LogDataFile.close();
  
#ifdef aUSESTEM
  // Start the serail link thread
  m_stem.startLinkThread(m_settings);
  printf("Stem %i\n",m_stem.isConnected());
#endif
  
#ifdef aUSEKALMANFILTER
  m_filter.init(1.0, 0.0, 5.0);
#else
  m_filter.init();
#endif
  
  m_filterAvg.init();
  
}

////////////////////////////////////////////////////////////////////

void 
acpTemperature::history_update(const int value)
{
  // shift values to the left
  for (int i = 0; i < (m_historySize - 1); i++)
    m_history[i] = m_history[i + 1];
  
  // add the new value in
  m_history[m_historySize - 1] = value;
}

////////////////////////////////////////////////////////////////////

void 
acpTemperature::history_print()
{
  for (int i = 0; i < m_historySize; i++)
    printf("h[%i] = %d\n",i,m_history[i]);
}

////////////////////////////////////////////////////////////////////
// Function to send a message out using system call
void 
acpTemperature::sendMsg(const int status)
{
  // Place holder for message to get send
  acpString msg;
  acpString info;
  acpString subject;
  
  printf("Sending msg to %s \n",m_msgRecepient);
  
  // Message heading subject
  subject = "Status Update Message";
  
  // Build up a informational string 
  // to but in the message body
  switch (status) {
    case 1:
      info = "temperature is not ready\n";
      info += "but is getting warmer.";
      break;
    default:
      break;
  }
  
  //Build up the body email
  msg = "echo '";
  msg += info;
  msg += "'";
  
  // Pass the body information into the send mail command
  msg += " | mail -s '";
  msg += subject;
  msg += "' ";
  msg += m_msgRecepient;
  
  // Fire off the message
  system(msg);
  
}

////////////////////////////////////////////////////////////////////
// Function to record data to a file
// Time format is http://en.wikipedia.org/wiki/ISO_8601
void 
acpTemperature::record()
{
  float val = 0.0f;
  float valFilter;
  float valFilterAvg;
  
  ofstream LogDataFile((char*)m_dataFileName, ios::app);

  m_sampleNum++;
  
#ifdef aUSESTEM
  // sample until we get a reading that is big or we try too much
  val = m_stem.A2D_RD(2, 0);
  
  if (val < 0.0f) val = 0.0f;
  
#else
  val = 0.0;
#endif
  
  // Run a filter on the data
  valFilter = m_filter.update(val);
  valFilterAvg = m_filterAvg.update(val);
  
  printf("\t\tval = %2.3f \tvalFilter = %2.3f\tvalFilterAvg = %2.3f\n",val, valFilter, valFilterAvg);
  
  acpString valStorage;
  
  time_t rawtime;
  struct tm * timeinfo;
  
  time ( &rawtime );
  timeinfo = localtime ( &rawtime );
  
  char buf[50];
  strftime(buf, 50, "%G-%m-%eT%k:%M:%S", timeinfo);
  
  acpString timestamp(buf);
  
  valStorage = timestamp;
  valStorage += ",";
  
  valStorage += (float)val;
  valStorage += ",";
  valStorage += (float)valFilter;
  valStorage += ",";
  valStorage += (float)valFilterAvg;
  valStorage += ",";  
  valStorage += m_sampleNum;
  valStorage += "\n";
  
  LogDataFile << (char*) valStorage;
  LogDataFile.close();
  
  
  // Delay a bit
  aIO_MSSleep(m_ioref, m_delay, NULL);
  
}


////////////////////////////////////////////////////////////////////


int 
main(const int argc,
     const char* argv[])
{
  int retVal = 0;
  
  { // scope ensures all destructors are called before memory leak checks
    try {
      acpTemperature temperature;
      
      temperature.init();
      
      for (int i = 0; i < 1000; i++) {
	temperature.record();
	printf("i = %d",i);
      }
      
      //temperature.sendMsg(1);			
      
    } catch(acpException& exception) {
      aAssert(0);
      printf("Exception: %s\n", exception.msg());
    } catch(...) {
      printf("bailing with uncaught exception\n");
    }
  }
  
#ifndef aWIN
  // Windows does memory checking in a different context, others do it here.
  retVal += aLeakCheckCleanup();
#endif
  
  return(retVal);
  
} /* main */
